﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Wizard.UI;
using System.IO;
using Toub.MediaCenter.Dvrms.Metadata;
using TvdbLib;
using System.Text.RegularExpressions;
using System.Xml;

namespace DVRMS_Renamer
{
    public static class Common
    {
        private static SeriesList mcolSeries = new SeriesList();
        private static List<string> colFilenames = new List<string>();

        #region Find and read DVR-MS files

        public static void LoadDVRMSFiles(Wizard.UI.InternalWizardPage pg, ProgressBar pgrProgress, Label lblWorking, ListView lstItems)
        {
            string[] fileEntries = GetFiles(Globals.selectedFolderToScan,
                new string[] { ".ts", ".dvr-ms", ".m4v" },
                null, SearchOption.AllDirectories);

            lstItems.Items.Clear();
            pgrProgress.Value = 0;
            pgrProgress.Maximum = fileEntries.Length;
            System.Threading.Thread.Sleep(50);
            pgrProgress.Refresh();
            pg.Refresh();
            Application.DoEvents();

            foreach (string file in fileEntries)
            {
                FileInfo f = new FileInfo(file);
                lblWorking.Text = "Reading " + f.Name + "...";
                lblWorking.Refresh();
                pg.Refresh();
                Application.DoEvents();

                File newFile;
                if (Path.GetExtension(file) == ".dvr-ms")
                    newFile = readDVRMSMetadata(file);
                else
                    newFile = readXMLMetadata(file);

                ListViewItem lstItem = new ListViewItem(new string[] {
                        newFile.originalFileName,
                        newFile.showTitle,
                        newFile.originalBroadcast.ToShortDateString(),
                        newFile.subTitle,
                        newFile.subTitleDescription}, -1);

                lstItem.Checked = true;
                lstItem.Tag = newFile;
                lstItems.Items.Add(lstItem);

                pgrProgress.Value += 1;
                System.Threading.Thread.Sleep(50);
                pgrProgress.Refresh();
                pg.Refresh();
                Application.DoEvents();
            }

            pgrProgress.Value = pgrProgress.Maximum;
            System.Threading.Thread.Sleep(1000);
            pgrProgress.Refresh();
            pg.Refresh();
            Application.DoEvents();

            lstItems.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
        }

        private static string[] GetFiles(string sourceFolder, string[] exts, string[] exclude, System.IO.SearchOption searchOption)
        {
            try
            {
                string[] files = Directory.EnumerateFiles(sourceFolder, "*.*", searchOption)
                    .Where(f => exts.Contains(Path.GetExtension(f), StringComparer.OrdinalIgnoreCase)).ToArray();

                if (exclude != null)
                {
                    IEnumerable<string> rxfilters = from filter in exclude select string.Format("^{0}$", filter.Replace(@"\", @"\\").Replace(".", @"\.").Replace("*", ".*").Replace("?", "."));
                    Regex regex = new Regex(string.Join("|", rxfilters.ToArray()));

                    return files.Where(f => !regex.Match(f).Success).ToArray();
                }
                else
                    return files;
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("Error getting file list for {0}\r\n\r\n", sourceFolder) + ex.ToString(),
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                return null;
            }
        }
        
        private static File readDVRMSMetadata(string pathFile)
        {
            string strTitle;
            DateTime dtmOriginalBroadcast;
            string strSubTitle;
            string strSubTitleDescription;

            DvrmsMetadataEditor dvrmsFile = new DvrmsMetadataEditor(pathFile);

            IDictionary dvrmsMetadata = dvrmsFile.GetAttributes();

            strTitle = ((MetadataItem)dvrmsMetadata["Title"]).Value.ToString();
            try
            {
                dtmOriginalBroadcast = (DateTime)((MetadataItem)dvrmsMetadata["WM/MediaOriginalBroadcastDateTime"]).Value;
            }
            catch
            {
                dtmOriginalBroadcast = new DateTime();
            }
            strSubTitle = ((MetadataItem)dvrmsMetadata["WM/SubTitle"]).Value.ToString();
            strSubTitleDescription = ((MetadataItem)dvrmsMetadata["WM/SubTitleDescription"]).Value.ToString();

            File theFile = new File();
            theFile.originalFileName = pathFile;
            theFile.showTitle = strTitle;
            theFile.originalBroadcast = dtmOriginalBroadcast;
            theFile.subTitle = strSubTitle;
            theFile.subTitleDescription = strSubTitleDescription;

            return theFile;
        }

        private static File readXMLMetadata(string pathFile)
        {
            string strTitle;
            DateTime dtmOriginalBroadcast;
            string strSubTitle;
            string strSubTitleDescription;

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(Path.Combine(Path.GetDirectoryName(pathFile), Path.GetFileNameWithoutExtension(pathFile)) + ".xml");

            //* Get elements.
            XmlNodeList title = xmlDoc.SelectNodes("/tags/tag/SimpleTag[name='TITLE']/value");
            XmlNodeList comment = xmlDoc.SelectNodes("/tags/tag/SimpleTag[name='COMMENT']/value");
            XmlNodeList girlCellPhoneNumber = xmlDoc.GetElementsByTagName("gPhone");

            strTitle = title[0].InnerText;
            
            dtmOriginalBroadcast = new DateTime();
            strSubTitle = "";
            strSubTitleDescription = comment[0].InnerText;
            
            File theFile = new File();
            theFile.originalFileName = pathFile;
            theFile.showTitle = strTitle;
            theFile.originalBroadcast = dtmOriginalBroadcast;
            theFile.subTitle = strSubTitle;
            theFile.subTitleDescription = strSubTitleDescription;
            
            return theFile;
        }

        #endregion

        #region Match files to thetvdb.com

        static public void ProcessItems(Wizard.UI.InternalWizardPage pg, ProgressBar pgrProgress, Label lblWorking, ListView lstItems)
        {
            lstItems.Items.Clear();
            pgrProgress.Value = 0;
            pgrProgress.Maximum = Globals.selectedFilesToScan.Count;
            System.Threading.Thread.Sleep(50);
            pgrProgress.Refresh();
            pg.Refresh();
            Application.DoEvents();

            foreach (File file in Globals.selectedFilesToScan)
            {
                readTheTVDB(file, lblWorking);

                ListViewItem lstItem = new ListViewItem(new string[] {
                            file.originalFileName,
                            file.newFilename,
                            file.confidenceDisplay,
                            file.subTitle,
                            file.subTitleDescription}, -1);

                if (file.confidence == 0)
                    lstItem.Checked = false;
                else
                {
                    if (file.newFilename == file.originalFileName)
                        lstItem.Checked = false;
                    else
                        lstItem.Checked = true;
                }

                lstItem.Tag = file;
                lstItems.Items.Add(lstItem);

                pgrProgress.Value += 1;
                System.Threading.Thread.Sleep(50);
                pgrProgress.Refresh();
                pg.Refresh();
                Application.DoEvents();
            }
            
            pgrProgress.Value = pgrProgress.Maximum;
            System.Threading.Thread.Sleep(1000);
            pg.Refresh();
            Application.DoEvents();

            lstItems.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
        }

        private static void readTheTVDB(File file, Label lblWorking)
        {
            // See if the series exists in the local cache first
            Series theSeries = checkCache(file.showTitle);
            Episode matchedEpisode = null;

            // Check thetvdb if not found in the cache
            if (theSeries == null)
            {
                lblWorking.Text = "Getting " + file.showTitle + " show details from thetvdb.com...";
                lblWorking.Refresh();

                theSeries = checkTVDV(file.showTitle);
                if (theSeries != null) mcolSeries.Add(theSeries);
            }

            // Now, if we have a series we'll try to match an episode
            if (theSeries != null)
            {
                lblWorking.Text = "Trying to match " + file.originalFileName + " to an episode...";
                lblWorking.Refresh();

                matchedEpisode = theSeries.MatchEpisode(file.originalBroadcast, file.subTitle, file.subTitleDescription);
            }

            if (matchedEpisode != null)
            {
                file.newFilename = "S" + matchedEpisode.SeasonNumber.ToString("00") +
                    "E" + matchedEpisode.EpisodeNumber.ToString("00") +
                    " - " + matchedEpisode.EpisodeName + Path.GetExtension(file.originalFileName);
                
                file.newFilename = Regex.Replace(file.newFilename, @"[?:\/*""<>|]", "");

                // Check for local files that will have a duplicate name
                int counter = 1;
                while (colFilenames.Exists(
                    delegate(string n)
                    {
                        return n == file.newFilename;
                    }))
                {
                    file.newFilename = Path.GetFileNameWithoutExtension(file.newFilename) + " (" + counter.ToString() + ")" + Path.GetExtension(file.newFilename);
                    counter += 1;
                }
                colFilenames.Add(file.newFilename);

                file.confidence = matchedEpisode.Confidence;
                file.url = matchedEpisode.URL;
                file.urlCaption = matchedEpisode.URLCaption;
            }
            else
            {
                if (theSeries != null)
                {
                    file.url = theSeries.url;
                    file.urlCaption = theSeries.urlCaption;
                }
            }
        }

        private static Series checkCache(string seriesTitle)
        {
            // Check the cache
            return mcolSeries.Find(seriesTitle);
        }

        private static Series checkTVDV(string seriesName)
        {
            Series theSeries = new Series();
            TvdbHandler tvdb = new TvdbHandler("177827A570CAB316");
            int id = 0;

            List<TvdbLib.Data.TvdbSearchResult> tvdbResults = tvdb.SearchSeries(seriesName);

            if (tvdbResults.Count > 1)
            {
                frmSelectSeries select = new frmSelectSeries(tvdbResults);
                select.ShowDialog();
                id = select.id;
                select = null;
            }

            if (tvdbResults.Count == 1)
            {
                id = tvdbResults[0].Id;
            }

            if (id != 0)
            {
                try
                {
                    TvdbLib.Data.TvdbSeries tvdbSeries = tvdb.GetSeries(id, TvdbLib.Data.TvdbLanguage.DefaultLanguage, true, false, false);

                    theSeries.seriesName = tvdbSeries.SeriesName.Trim();
                    theSeries.originalBroadcast = tvdbSeries.FirstAired;
                    theSeries.subTitleDescription = tvdbSeries.Overview.Trim();
                    theSeries.url = "http://thetvdb.com/?tab=seasonall" +
                        "&id=" + tvdbSeries.Id.ToString() +
                        "&lid=" + TvdbLib.Data.TvdbLanguage.DefaultLanguage.Id.ToString();
                    theSeries.urlCaption = "Click to view the series on thetvdv.com website";

                    for (int i = 0; i < tvdbSeries.Episodes.Count; i++)
                    {
                        string url = "";
                        string urlCaption = "";

                        url = "http://thetvdb.com/?tab=episode" +
                            "&seriesid=" + tvdbSeries.Id.ToString() +
                            "&seasonid=" + tvdbSeries.Episodes[i].SeasonId.ToString() +
                            "&id=" + tvdbSeries.Episodes[i].Id.ToString() +
                            "&lid=" + TvdbLib.Data.TvdbLanguage.DefaultLanguage.Id.ToString();
                        urlCaption = "Click to view the episode on thetvdv.com website";

                        theSeries.EpisodeAdd(new Episode(tvdbSeries.Episodes[i].SeasonNumber,
                            tvdbSeries.Episodes[i].EpisodeNumber, tvdbSeries.Episodes[i].EpisodeName.Trim(),
                            tvdbSeries.Episodes[i].FirstAired, tvdbSeries.Episodes[i].Overview.Trim(),
                            url, urlCaption));
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed to read the series data from thetvdb.com.\n\n" + ex.ToString(),
                        "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                }
                return theSeries;
            }
            else
            {
                // Give the user the option to choose!
                return null;
            }
        }

        #endregion

        #region Check for duplicates

        public static void CheckForDuplicates(Wizard.UI.InternalWizardPage pg, ProgressBar pgrProgress, Label lblWorking, ListView lstItems)
        {
            lstItems.Items.Clear();
            pgrProgress.Value = 0;
            pgrProgress.Maximum = Globals.selectedFilesToRename.Count;
            System.Threading.Thread.Sleep(50);
            pgrProgress.Refresh();
            pg.Refresh();
            Application.DoEvents();

            foreach (File file in Globals.selectedFilesToRename)
            {
                string[] fileEntries = Directory.GetFiles(Globals.selectedCompareFolder, "*.dvr-ms", SearchOption.AllDirectories);

                foreach (string existingFile in fileEntries)
                {
                    if (Path.GetFileName(existingFile).ToLower() == file.newFilename.ToLower())
                    {
                        ListViewItem lstItem = new ListViewItem(new string[] {
                            file.newFilename}, -1);

                        lstItem.Checked = true;
                        lstItem.Tag = file;
                        lstItems.Items.Add(lstItem);
                    }
                }

                pgrProgress.Value += 1;
                System.Threading.Thread.Sleep(50);
                pgrProgress.Refresh();
                pg.Refresh();
                Application.DoEvents();
            }

            pgrProgress.Value = pgrProgress.Maximum;
            System.Threading.Thread.Sleep(1000);
            pg.Refresh();
            Application.DoEvents();

            lstItems.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
        }

        #endregion
    }
}
